use super::*;

#[derive(Debug, Clone, Default)]
pub struct Glyph {
	layers: Vec<Layer>,
	glyphname: String,
	export: Option<bool>,
	kern_left: Option<String>,
	kern_right: Option<String>,
	unicode: Vec<String>,
	category: Option<String>,
	script: Option<String>,
	sub_category: Option<String>,
	production_name: Option<String>,
}
impl FromPlist for Glyph {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		let mut this = Self::default();
		r.expect(Event::Dictionary)?;
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("category") => this.category = r.parse()?,
				Event::String("glyphname") => this.glyphname = r.parse()?,
				Event::String("kernLeft") => this.kern_left = r.parse()?,
				Event::String("leftKerningGroup") => this.kern_left = r.parse()?,
				Event::String("kernRight") => this.kern_right = r.parse()?,
				Event::String("rightKerningGroup") => this.kern_right = r.parse()?,
				Event::String("script") => this.script = r.parse()?,
				Event::String("subCategory") => this.sub_category = r.parse()?,
				Event::String("unicode") => match r.peak().read_next()? {
					Event::Array => this.unicode = r.parse()?,
					Event::String(s) => {
						r.read_next()?;
						this.unicode.push(s.into())
					}
					_ => return Err(Error::Msg("expect unicode")),
				},
				Event::String("productionName") => this.production_name = r.parse()?,
				Event::String("production") => this.production_name = r.parse()?,
				Event::String("export") => this.export = r.parse()?,
				Event::String("layers") => this.layers = r.parse()?,

				Event::String("userData") => _ = Value::from_plist(r)?,
				Event::String("metricWidth") => _ = Value::from_plist(r)?,
				Event::String("metricLeft") => _ = Value::from_plist(r)?,
				Event::String("metricRight") => _ = Value::from_plist(r)?,

				e => return Err(Error::unexpect(e)),
			}
		}
		Ok(this)
	}
}
impl Glyph {
	pub fn load(base: impl AsRef<std::path::Path>) -> Result<Self, Error> {
		let content = std::fs::read_to_string(base).map_err(|e| Error::Io(format!("{:?}", e)))?;
		let mut parse = plist::Parser::new(&content);
		match Self::from_plist(&mut parse) {
			Ok(this) => Ok(this),
			Err(e) => {
				println!("{:?}", parse.pos());
				Err(e)
			}
		}
	}
}

#[derive(Debug, Clone, Default)]
struct Layer {
	name: String,
	layer_id: String,
	associated_master_id: Option<String>,
	width: Option<f64>,
	vert_width: Option<f64>,
	vert_origin: Option<f64>,
	shapes: Vec<Shape>,
	paths: Vec<Path>,
	components: Vec<Component>,
	anchors: Vec<Anchor>,
	attributes: LayerAttributes,
}
impl FromPlist for Layer {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("Name") => this.name = r.parse()?,
				Event::String("layerId") => this.layer_id = r.parse()?,
				Event::String("associatedMasterId") => this.associated_master_id = r.parse()?,
				Event::String("width") => this.width = r.parse()?,
				Event::String("vertWidth") => this.vert_width = r.parse()?,
				Event::String("vertOrigin") => this.vert_origin = r.parse()?,
				Event::String("shapes") => this.shapes = r.parse()?,
				Event::String("paths") => this.paths = r.parse()?,
				Event::String("components") => this.components = r.parse()?,
				Event::String("anchors") => this.anchors = r.parse()?,
				Event::String("attributes") => this.attributes = r.parse()?,
				Event::String("attr") => this.attributes = r.parse()?,

				Event::String("userData") => _ = Value::from_plist(r)?,
				Event::String("guides") => _ = Value::from_plist(r)?,

				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}
#[derive(Debug, Clone, Default)]
pub struct LayerAttributes {
	pub coordinates: Vec<f64>,
	pub color: bool,
	// in the same order that axes are declared for the font
	pub axis_rules: Vec<AxisRule>,
}
impl FromPlist for LayerAttributes {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("coordinates") => this.coordinates = r.parse()?,
				Event::String("color") => this.color = r.parse()?,
				Event::String("axisRules") => this.axis_rules = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
pub struct AxisRule {
	// if missing, assume default min/max for font
	pub min: Option<i64>,
	pub max: Option<i64>,
}
impl FromPlist for AxisRule {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("min") => this.min = r.parse()?,
				Event::String("max") => this.max = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct Shape {
	closed: Option<bool>,
	nodes: Vec<Node>,
	glyph_name: Option<String>,

	anchor: Option<String>,
	transform: Option<String>, // v2
	pos: Vec<f64>,             // v3
	angle: Option<f64>,        // v3
	scale: Vec<f64>,           // v3

	attributes: ShapeAttributes,
}
impl FromPlist for Shape {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("closed") => this.closed = r.parse()?,
				Event::String("nodes") => this.nodes = r.parse()?,

				Event::String("glyphName") => this.glyph_name = r.parse()?,
				Event::String("ref") => this.glyph_name = r.parse()?,
				Event::String("name") => this.glyph_name = r.parse()?,

				Event::String("anchor") => this.anchor = r.parse()?,
				Event::String("transform") => this.transform = r.parse()?,
				Event::String("pos") => this.pos = r.parse()?,
				Event::String("angle") => this.angle = r.parse()?,
				Event::String("scale") => this.scale = r.parse()?,

				Event::String("attributes") => this.attributes = r.parse()?,
				Event::String("attr") => this.attributes = r.parse()?,

				Event::String("alignment") => _ = Value::from_plist(r)?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

/// <https://github.com/schriftgestalt/GlyphsSDK/blob/Glyphs3/GlyphsFileFormat/GlyphsFileFormatv3.md#spec-glyphs-3-path>
#[derive(Debug, Clone, Default)]
pub struct Path {
	pub closed: bool,
	pub nodes: Vec<Node>,
	pub attributes: ShapeAttributes,
}
impl FromPlist for Path {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("closed") => this.closed = r.parse()?,
				Event::String("nodes") => this.nodes = r.parse()?,

				Event::String("attributes") => this.attributes = r.parse()?,
				Event::String("attr") => this.attributes = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

/// <https://github.com/schriftgestalt/GlyphsSDK/blob/Glyphs3/GlyphsFileFormat/GlyphsFileFormatv3.md#spec-glyphs-3-component>
#[derive(Debug, Clone, Default)]
pub struct Component {
	/// The glyph this component references
	pub name: String,
	/// meh
	pub transform: Affine,
	/// An alternative anchor name used during anchor propagation
	///
	/// For instance, if an acute accent is a component of a ligature glyph,
	/// we might rename its 'top' anchor to 'top_2'
	pub anchor: Option<String>,
	pub attributes: ShapeAttributes,
}
impl FromPlist for Component {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("transform") => {
					let s = r.expect_string()?;
					let mut r = plist::Parser::new(s);
					r.expect(Event::Dictionary)?;
					let values: [f64; 6] = [r.parse()?, r.parse()?, r.parse()?, r.parse()?, r.parse()?, r.parse()?];
					r.expect(Event::End)?;
					this.transform = Affine::new(values);
				}

				Event::String("anchor") => this.anchor = r.parse()?,
				Event::String("attributes") => this.attributes = r.parse()?,
				Event::String("attr") => this.attributes = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone)]
pub struct Affine(pub [f64; 6]);
impl Affine {
	pub const IDENTITY: Affine = Affine::scale(1.0);
	pub const FLIP_Y: Affine = Affine::new([1.0, 0., 0., -1.0, 0., 0.]);
	pub const FLIP_X: Affine = Affine::new([-1.0, 0., 0., 1.0, 0., 0.]);
	#[inline(always)]
	pub const fn new(c: [f64; 6]) -> Affine {
		Affine(c)
	}
	#[inline(always)]
	pub const fn scale(s: f64) -> Affine {
		Affine([s, 0.0, 0.0, s, 0.0, 0.0])
	}
}
impl Default for Affine {
	#[inline(always)]
	fn default() -> Affine {
		Affine::IDENTITY
	}
}

#[derive(Debug, Clone, Default)]
pub struct ShapeAttributes {
	pub gradient: Gradient,
}
impl FromPlist for ShapeAttributes {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("gradient") => this.gradient = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
pub struct Gradient {
	pub start: Vec<f64>,
	pub end: Vec<f64>,
	pub colors: Vec<Color>,
	pub style: String,
}
impl FromPlist for Gradient {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("start") => this.start = r.parse()?,
				Event::String("end") => this.end = r.parse()?,
				Event::String("colors") => this.colors = r.parse()?,
				Event::String("type") => this.style = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
pub struct Color {
	pub r: i64,
	pub g: i64,
	pub b: i64,
	pub a: i64,
	// The position on the color line, see <https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-lines>
	pub stop_offset: f64,
}
impl FromPlist for Color {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Array)?;
		let colors: Vec<i64> = r.parse()?;
		let stop_offset: f64 = r.parse()?;
		r.expect(Event::End)?;
		match *colors.as_slice() {
			// Grayscale
			[black, alpha] => Ok(Color {
				r: black,
				g: black,
				b: black,
				a: alpha,
				stop_offset: stop_offset.into(),
			}),
			// RGB
			[r, g, b, a] => Ok(Color {
				r,
				g,
				b,
				a,
				stop_offset: stop_offset.into(),
			}),
			// 5 is CMYK, match python by not supporting that
			_ => Err(Error::Msg("expect color")),
		}
	}
}

#[derive(Debug, Clone)]
pub struct Node {
	pub pt: Point,
	pub node_type: NodeType,
}
impl Node {
	fn parse_v3(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Array)?;
		let x: f64 = r.parse()?;
		let y: f64 = r.parse()?;
		let t: NodeType = r.expect_string()?.parse().map_err(|s| Error::Unexpect(s))?;
		match r.read_next()? {
			Event::End => {}
			Event::Dictionary => {
				loop {
					match r.read_next()? {
						Event::End => break,
						_ => {}
					}
				}
				r.expect(Event::End)?;
			}
			e => return Err(Error::unexpect(e)),
		}
		Ok(Self {
			pt: Point { x, y },
			node_type: t,
		})
	}
	fn parse_v2(r: &mut Parser<'_>) -> Result<Self, Error> {
		let x: f64 = r.parse()?;
		let y: f64 = r.parse()?;
		let t: NodeType = r.expect_string()?.parse().map_err(|s| Error::Unexpect(s))?;
		Ok(Self {
			pt: Point { x, y },
			node_type: t,
		})
	}
}
impl FromPlist for Node {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		match r.peak().read_next()? {
			Event::Array => Self::parse_v3(r),
			Event::String(s) => {
				r.read_next()?;
				Self::parse_v2(&mut Parser::new(s))
			}
			e => return Err(Error::unexpect(e)),
		}
	}
}

#[derive(Debug, Clone)]
pub enum NodeType {
	Line,
	LineSmooth,
	OffCurve,
	Curve,
	CurveSmooth,
	QCurve,
	QCurveSmooth,
}
impl std::str::FromStr for NodeType {
	type Err = String;
	fn from_str(s: &str) -> Result<Self, Self::Err> {
		match s {
			// Glyphs 2 style
			"LINE" => Ok(NodeType::Line),
			"LINE SMOOTH" => Ok(NodeType::LineSmooth),
			"OFFCURVE" => Ok(NodeType::OffCurve),
			"CURVE" => Ok(NodeType::Curve),
			"CURVE SMOOTH" => Ok(NodeType::CurveSmooth),
			"QCURVE" => Ok(NodeType::QCurve),
			"QCURVE SMOOTH" => Ok(NodeType::QCurveSmooth),
			// Glyphs 3 style
			"l" => Ok(NodeType::Line),
			"ls" => Ok(NodeType::LineSmooth),
			"o" => Ok(NodeType::OffCurve),
			"c" => Ok(NodeType::Curve),
			"cs" => Ok(NodeType::CurveSmooth),
			"q" => Ok(NodeType::QCurve),
			"qs" => Ok(NodeType::QCurveSmooth),
			_ => Err(format!("unknown node type {s}")),
		}
	}
}

#[derive(Debug, Clone, Default)]
struct Anchor {
	name: String,
	pos: Option<Point>,       // v3
	position: Option<String>, // v2
}
impl FromPlist for Anchor {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("pos") => this.pos = r.parse()?,
				Event::String("position") => this.position = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
pub struct Point {
	/// The x coordinate.
	pub x: f64,
	/// The y coordinate.
	pub y: f64,
}
impl FromPlist for Point {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Array)?;
		let x: f64 = r.parse()?;
		let y: f64 = r.parse()?;
		r.expect(Event::End)?;
		Ok(Self { x, y })
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	#[test]
	fn test_load() {
		_ = Glyph::load("assets/fontc/glyphs3/infinity.glyphspackage/glyphs/infinity.glyph").unwrap();
	}
}
